//
//  PCTestPickerViewController.m
//  PCTestPickerViewController
//
//  Created by lpc on 16/4/20.
//  Copyright © 2016年 lpc. All rights reserved.
//

#import "PCTestPickerViewController.h"
#import <objc/runtime.h>
@class AssistiveTouchView;


#pragma mark ================================
#pragma mark ================================
#pragma mark -- AssistiveTouchView --

typedef void(^AssistiveClickBlock)();
#define k_AssistiveTouch_Width      60
#define kOffSet                     (k_AssistiveTouch_Width / 2)
#define BLOCK_SELF                  __block __typeof(self) blockSelf = self;
#define K_BackgroundView_COLOR      ([UIColor greenColor])

@interface AssistiveTouchView : UIView

@property (nonatomic,assign) CGPoint startPoint;            //触摸起始点
@property (nonatomic,assign) CGPoint endPoint;              //触摸结束点
@property (nonatomic,copy) AssistiveClickBlock clickBlock;
@property (nonatomic,strong) UIView *backgroundView;        //背景视图
@property (nonatomic,strong) UIDynamicAnimator *animator;   //物理仿真动画
@property (nonatomic,assign) BOOL isPickerControllerShowing;
@end


@implementation AssistiveTouchView

//初始化
-(instancetype)initWithFrame:(CGRect)frame{

    frame.size.width = k_AssistiveTouch_Width;
    frame.size.height = k_AssistiveTouch_Width;

    self = [super initWithFrame:frame];
    if (self) {
        [self customSubViews];
    }
    return self;
}

- (void)customSubViews
{
    //背景视图
    _backgroundView = [[UIView alloc]initWithFrame:self.bounds];
    _backgroundView.layer.cornerRadius = _backgroundView.frame.size.width / 2;
    _backgroundView.clipsToBounds = YES;
    _backgroundView.backgroundColor = [K_BackgroundView_COLOR colorWithAlphaComponent:0.7];
    _backgroundView.userInteractionEnabled = NO;
    [self addSubview:_backgroundView];

    //中心视图
    CGFloat centerOff = 8;
    UIView *centerView = [[UIView alloc]initWithFrame:CGRectMake(centerOff, centerOff, CGRectGetWidth(self.frame) - 2 * centerOff, CGRectGetHeight(self.frame) - 2 * centerOff)];
    centerView.layer.cornerRadius = centerView.frame.size.width / 2;
    centerView.clipsToBounds = YES;
    centerView.backgroundColor = [K_BackgroundView_COLOR colorWithAlphaComponent:0.8f];
    centerView.userInteractionEnabled = NO;
    [self addSubview:centerView];

    self.layer.cornerRadius = k_AssistiveTouch_Width / 2;
    self.isPickerControllerShowing = NO;
    [self highlightAnimation];
}


#pragma mark -- Touches events --

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *startTouch = [touches anyObject];
    self.startPoint = [startTouch locationInView:self.superview];
    [self.animator removeAllBehaviors];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *movedTouch = [touches anyObject];
    self.center = [movedTouch locationInView:self.superview];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *endTouch = [touches anyObject];
    self.endPoint = [endTouch locationInView:self.superview];

    //判断是否移动了视图 (误差范围5)
    CGFloat errorRange = 5;

    CGFloat off_X = self.endPoint.x - self.startPoint.x;
    CGFloat off_Y = self.endPoint.y - self.startPoint.y;

    if (ABS(off_X) <= errorRange && ABS(off_Y) <= errorRange) {
        //未移动,打开控制器
        if (self.clickBlock) {
            self.clickBlock();
        }
    }
    else{
        //移动
        self.center = self.endPoint;

        //计算距离最近的边缘 吸附到边缘停靠
        CGFloat superwidth = self.superview.bounds.size.width;
        CGFloat superheight = self.superview.bounds.size.height;

        CGFloat endX = self.endPoint.x;
        CGFloat endY = self.endPoint.y;

        CGFloat topRange = endY;                    //上距离
        CGFloat bottomRange = superheight - endY;   //下距离
        CGFloat leftRange = endX;                   //左距离
        CGFloat rightRange = superwidth - endX;     //右距离


        //比较上下左右距离 取出最小值
        CGFloat minRangeTB = topRange > bottomRange ? bottomRange : topRange;   //获取上下最小距离
        CGFloat minRangeLR = leftRange > rightRange ? rightRange : leftRange;   //获取左右最小距离
        CGFloat minRange = minRangeTB > minRangeLR ? minRangeLR : minRangeTB;   //获取最小距离


        //判断最小距离属于上下左右哪个方向 并设置该方向边缘的point属性
        CGPoint minPoint;

        if (minRange == topRange) {
            //上
            endX = endX - kOffSet < 0 ? kOffSet : endX;
            endX = endX + kOffSet > superwidth ? superwidth - kOffSet : endX;
            minPoint = CGPointMake(endX , 0 + kOffSet);
        }
        else if(minRange == bottomRange){
            //下
            endX = endX - kOffSet < 0 ? kOffSet : endX;
            endX = endX + kOffSet > superwidth ? superwidth - kOffSet : endX;
            minPoint = CGPointMake(endX , superheight - kOffSet);
        }
        else if(minRange == leftRange){
            //左
            endY = endY - kOffSet < 0 ? kOffSet : endY;
            endY = endY + kOffSet > superheight ? superheight - kOffSet : endY;
            minPoint = CGPointMake(0 + kOffSet , endY);
        }
        else if(minRange == rightRange){
            //右
            endY = endY - kOffSet < 0 ? kOffSet : endY;
            endY = endY + kOffSet > superheight ? superheight - kOffSet : endY;
            minPoint = CGPointMake(superwidth - kOffSet , endY);
        }

        //添加吸附物理行为
        UIAttachmentBehavior *attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self attachedToAnchor:minPoint];
        [attachmentBehavior setLength:0];
        [attachmentBehavior setDamping:0.1];
        [attachmentBehavior setFrequency:5];
        [self.animator addBehavior:attachmentBehavior];
    }
}


#pragma mark ---LazyLoading

- (UIDynamicAnimator *)animator {
    if (!_animator) {
        // 创建物理仿真器(ReferenceView : 仿真范围)
        _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.superview];
    }
    return _animator;
}

#pragma mark ---BreathingAnimation 呼吸动画 ---
- (void)highlightAnimation {

    BLOCK_SELF;
    [UIView animateWithDuration:1.5f animations:^{
        blockSelf.backgroundView.backgroundColor = [blockSelf.backgroundView.backgroundColor colorWithAlphaComponent:0.1f];
    } completion:^(BOOL finished) {
        [blockSelf darkAnimation];
    }];
}

- (void)darkAnimation{

    BLOCK_SELF;
    [UIView animateWithDuration:1.5f animations:^{
        blockSelf.backgroundView.backgroundColor = [blockSelf.backgroundView.backgroundColor colorWithAlphaComponent:0.6f];
    } completion:^(BOOL finished) {
        [blockSelf highlightAnimation];
    }];
}

@end



#pragma mark ================================
#pragma mark ================================
#pragma mark -- PCTestPickerViewController --

#define K_Search_History_Key        @"K_Search_History_Key"

static AssistiveTouchView *_assistive = nil;
static BOOL _isHasShown = NO;
static NSArray *_testArray = nil;
static BOOL _isPrefixTest = YES;

@interface PCTestPickerViewController () <UITableViewDataSource,UITableViewDelegate,UISearchBarDelegate>
{
    NSArray *totalArray;
    NSArray *tempArray;
    NSMutableArray *historyArray;
}

@property (nonatomic,strong) UITableView *tableView;

@end

@implementation PCTestPickerViewController

- (void)viewDidAppear:(BOOL)animated {

    [super viewDidAppear:animated];

    UISearchBar *searchBar = (UISearchBar *)self.navigationItem.titleView;
    [searchBar becomeFirstResponder];

    [self findControllersAndSetUI];
    [[self class] setAssistiveHidden:NO];
}


- (void)viewDidLoad {
    [super viewDidLoad];

    [self customSubViews];
    [self loadHistoryData];
}

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    self.tableView.frame = self.view.bounds;
}

- (void)customSubViews
{
    self.view.backgroundColor = [UIColor whiteColor];
    self.edgesForExtendedLayout = UIRectEdgeNone;

    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismissPicker)];

    UISearchBar *searchBar = [[UISearchBar alloc] init];
    searchBar.placeholder = @"Search";
    searchBar.delegate = self;
    self.navigationItem.titleView = searchBar;

    [self.view addSubview:self.tableView];
}

- (void)findControllersAndSetUI {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        totalArray = [self getViewControllersInProject];
        tempArray = totalArray;

        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    });
}

- (void)loadHistoryData {
    NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:K_Search_History_Key];
    if (array) {
        historyArray = [array mutableCopy];
    }else{
        historyArray = [NSMutableArray array];
    }
}


#pragma mark -- Show --
+ (void)showFinderWithClassPrefix:(NSArray<NSString *> *)prefixArray
{
    [[self class] showWithArray:prefixArray isPrefix:YES];
}

+ (void)showFinderWithClassSuffix:(NSArray<NSString *> *)suffixArray
{
    [[self class] showWithArray:suffixArray isPrefix:NO];
}

+ (void)showWithArray:(NSArray<NSString *> *)array isPrefix:(BOOL)isPrefix
{
    BOOL isEmpty = YES;
    if (([array isKindOfClass:[NSArray class]] && array.count > 0)) {
        NSString *string = [array firstObject];
        if (string.length > 0) {
            isEmpty = NO;
        }
    }
    if (isEmpty) {
        NSLog(@"<<<<<<<<<<<<<<<<<<<<< Waring!!! Array can not be empty!");
    }

    _testArray = [array copy];
    _isPrefixTest = isPrefix;


    if(!_isHasShown) {
        _isHasShown = YES;

        UIWindow *keyWindow = [self getKeyWindow];
        _assistive = [[AssistiveTouchView alloc] initWithFrame:CGRectMake(CGRectGetWidth(keyWindow.frame) - 80 , keyWindow.frame.size.height - 190, 60, 60)];
        _assistive.clickBlock = ^{
            [[self class] showPickerController];
        };
        [keyWindow addSubview:_assistive];
        [keyWindow bringSubviewToFront:_assistive];
    }
}

+ (void)showPickerController {

    if (_assistive.isPickerControllerShowing) {
        return;
    }

    UIViewController *rootVC = [self getKeyWindow].rootViewController;
    PCTestPickerViewController *viewC = [PCTestPickerViewController new];
    UINavigationController *pickerNav = [[UINavigationController alloc] initWithRootViewController:viewC];
    [rootVC presentViewController:pickerNav animated:YES completion:^{
        _assistive.isPickerControllerShowing = YES;
    }];
}

+ (void)showViewController:(UIViewController *)controller {
    UIViewController *rootVC = [self getKeyWindow].rootViewController;

    if ([rootVC isKindOfClass:[UITabBarController class]]) {
        for (UINavigationController *naviVC in ((UITabBarController *)rootVC).viewControllers) {
            if ([naviVC isKindOfClass:[UINavigationController class]]) {
                [naviVC showViewController:controller sender:nil];
                return;
            }
        }
    }

    [rootVC showViewController:controller sender:nil];
}

+ (void)setAssistiveHidden:(BOOL)hidden{
    _assistive.hidden = hidden;
}

+ (UIWindow *)getKeyWindow {
    return [[UIApplication sharedApplication] keyWindow];
}

- (void)dismissPicker{
    [self dismissViewControllerAnimated:YES completion:nil];
    _assistive.isPickerControllerShowing = NO;
}


#pragma mark -- 找出工程中符合条件的所有Controller --
- (NSArray *)getViewControllersInProject
{
    int numClasses;
    Class * classes = NULL;

    classes = NULL;
    numClasses = objc_getClassList(NULL, 0);

    NSMutableArray *unSortedArray = [NSMutableArray array];

    NSArray *classPrefixArray = [_testArray copy];

    if (numClasses > 0 )
    {
        classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
        numClasses = objc_getClassList(classes, numClasses);

        for (int i = 0; i < numClasses; i++) {
            Class theClass = classes[i];
            NSString *className = [NSString stringWithUTF8String:class_getName(theClass)];
            for (NSString *classPrefix in classPrefixArray)
            {
                BOOL isShouldAdd = NO;
                if (_isPrefixTest) {
                    isShouldAdd = [className hasPrefix:classPrefix];
                }
                else{
                    isShouldAdd = [className hasSuffix:classPrefix];
                }
                
                if (isShouldAdd) {
                    if ([theClass isSubclassOfClass:[UIViewController class]]) {
                        if (![unSortedArray containsObject:className]) {
                            [unSortedArray addObject:className];
                        }
                    }
                }
            }
        }
        free(classes);
    }

    NSArray *finallyArray = [unSortedArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2 options:NSForcedOrderingSearch];
    }];

    return finallyArray;
}


#pragma mark - UITableViewDelegate && UITableViewDataSource -

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return section ? tempArray.count : historyArray.count;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return section ? @"Search ↓" : @"History ↓";
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *identifier = @"TestCellId";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    NSArray *dataArray = indexPath.section ? tempArray : historyArray;
    NSString *className = dataArray[indexPath.row];
    cell.textLabel.text = className;
    return cell;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [historyArray removeObjectAtIndex:indexPath.row];
    [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

    [[NSUserDefaults standardUserDefaults] setObject:historyArray forKey:K_Search_History_Key];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return !indexPath.section;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    NSArray *dataArray = nil;
    dataArray = indexPath.section ? tempArray : historyArray;
    NSString *className = dataArray[indexPath.row];

    [self addHistoryRecord:className];

    [self dismissViewControllerAnimated:YES completion:^{
        UIViewController *targetVC = [[NSClassFromString(className) alloc] init];
        [PCTestPickerViewController showViewController:targetVC];
        _assistive.isPickerControllerShowing = NO;
    }];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    [self.view endEditing:YES];
}

#pragma mark - UISearchBarDelegate

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    NSMutableArray *resultArray = [NSMutableArray array];
    for (NSString *className in totalArray) {
        NSString *upperClassName = [className uppercaseString];
        NSString *upperSearchText = [searchText uppercaseString];

        if ([upperClassName containsString:upperSearchText]) {
            [resultArray addObject:className];
        }
    }

    tempArray = searchText.length ? resultArray : totalArray;
    [self.tableView reloadData];
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    [searchBar resignFirstResponder];
}

- (void)addHistoryRecord:(NSString *)history {
    if ([historyArray indexOfObject:history] == NSNotFound) {
        [historyArray addObject:history];

        [[NSUserDefaults standardUserDefaults] setObject:historyArray forKey:K_Search_History_Key];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

- (UITableView *)tableView
{
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
        _tableView.delegate = self;
        _tableView.dataSource = self;
    }
    return _tableView;
}

@end
